/********************************************************************
	Created:	2011/02/22    11:03 
	Filename: 	EventTarget.cpp
	Author:		falconwang
*********************************************************************/

#include "EventTarget.h"

ES::EventTarget::EventTarget(void)
{

}

ES::EventTarget::~EventTarget(void)
{

}

void ES::EventTarget::AddEventListener(const std::string& _eType , EventListener* _listener)
{
	EL_Ptr listener(_listener);
	std::map<std::string , std::list<EL_Ptr> >::iterator p = m_Listners.find(_eType);
	if( p == m_Listners.end() )
	{
		std::list<EL_Ptr>  el ;
		el.push_back(listener) ;
		m_Listners[_eType] = el;
	}
	else
	{
		std::list<EL_Ptr>& el = p->second;

		std::list<EL_Ptr>::iterator pp;

		for (pp = el.begin(); pp != el.end(); pp++)
		{
			if (*(*pp) == *listener && (*pp)->IsDestroy() == false)
			{
				return; // has duplicated
			}
		}

		el.push_back(listener);
	}
}

void ES::EventTarget::RemoveEventListener(const std::string& _eType , EventListener* _listener)
{
	EL_Ptr listener(_listener);

	std::map<std::string, std::list<EL_Ptr> >::iterator p = m_Listners.find(_eType) ;
	if( p != m_Listners.end() )
	{	
		std::list<EL_Ptr>& el = p->second ;
		std::list<EL_Ptr>::iterator q = el.begin();
		while(q != el.end())
		{
			if(*((*q).Get()) == *(listener.Get()))
			{
				(*q)->Destroy() ;
				return ;
			}

			q++ ;
		}
	}	
}

bool ES::EventTarget::HasEventListener(const std::string& _eType) const
{
	std::map<std::string , std::list<EL_Ptr> >::const_iterator p = m_Listners.find(_eType);
	return p != m_Listners.end();
}

void ES::EventTarget::DispatchEvent(Event& _e)
{
	std::map<std::string, std::list<EL_Ptr> >::iterator p = m_Listners.find(_e.GetType());
	if( p != m_Listners.end() )
	{
		std::list<EL_Ptr>::iterator q ;
		std::list<EL_Ptr>& el = p->second ; 
		for ( q = el.begin(); q != el.end(); q ++ )
		{
			if(!(*q)->IsDestroy())
			{
				(*(*q))(_e) ; 
			}
		}
	}

	// user may delete listeners in event handle do not use this, use Event Manager to do this
	HandleDestroyEventListener();
}

void ES::EventTarget::HandleDestroyEventListener()
{
	std::map<std::string, std::list<EL_Ptr> >::iterator p;
	for (p = m_Listners.begin(); p != m_Listners.end(); p++)
	{
		std::list<EL_Ptr>& el = p->second ; 
		std::list<EL_Ptr>::iterator q = el.begin() ;

		while (q != el.end())
		{
			if((*q)->IsDestroy())
			{
				q = el.erase(q) ;
			}
			else
			{
				q ++ ;
			}
		}
	}
}

void ES::EventTarget::RemoveAllEventListeners()
{
	m_Listners.clear();
}